package com.fishbone.cloud.auth.customizer;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.boot.util.LambdaSafe;
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
import org.springframework.security.oauth2.provider.endpoint.AuthorizationEndpoint;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;

/**
 * @ClassName EndpointCustomizerProcessor
 * @Author huyaxi
 * @DATE 2020/4/3 15:42
 */
public class EndpointCustomizerProcessor implements BeanPostProcessor, BeanFactoryAware {

    private ListableBeanFactory beanFactory;

    private List<EndpointCustomizer> customizers;

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        if (bean instanceof AuthorizationEndpoint) {
            postProcessBeforeInitialization((AuthorizationEndpoint) bean);
        }
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }

    private void postProcessBeforeInitialization(AuthorizationEndpoint authorizationEndpoint) {
        LambdaSafe.callbacks(EndpointCustomizer.class, getCustomizers(), authorizationEndpoint)
                .withLogger(EndpointCustomizerProcessor.class)
                .invoke((customizer) -> customizer.customize(authorizationEndpoint));
    }

    private Collection<EndpointCustomizer> getCustomizers() {
        if (this.customizers == null) {
            // Look up does not include the parent context
            this.customizers = new ArrayList<>(getEndpointCustomizerBeans());
            this.customizers.sort(AnnotationAwareOrderComparator.INSTANCE);
            this.customizers = Collections.unmodifiableList(this.customizers);
        }
        return this.customizers;
    }

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        this.beanFactory = (ListableBeanFactory) beanFactory;
    }

    private Collection<EndpointCustomizer> getEndpointCustomizerBeans() {
        return (Collection) this.beanFactory.getBeansOfType(EndpointCustomizer.class, false, false).values();
    }
}
